home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / m2 / cat3src / cat / editutil.i < prev    next >
Text File  |  1997-10-26  |  47KB  |  1,473 lines

  1. IMPLEMENTATION MODULE EditUtil;
  2.  
  3. FROM SYSTEM     IMPORT  ADDRESS, ADR, TSIZE, CADR, LOC, LONGWORD, WORD, ASSEMBLER, CAST, CALLSYS, BYTE;
  4.  
  5. (* Megamax-Lib *)
  6.  
  7. FROM Storage    IMPORT ALLOCATE, DEALLOCATE, Inconsistent;
  8.  
  9. FROM GrafBase   IMPORT LongRect, Rectangle, Point;
  10.  
  11. IMPORT Storage, Strings, BinOps, StrConv, Block,
  12.        MOSGlobals, Keyboard, Directory, Paths, ShellMsg;
  13.  
  14. FROM Keyboard  IMPORT SpecialCode;
  15.  
  16. (* MagicLib *)
  17. IMPORT MagicAES, MagicVDI, MagicDOS, mtAlerts, mtDir;
  18.  
  19. (* CAT Module *)
  20. IMPORT CatFiles, MTE, CatGlobal;
  21.  
  22. FROM Void       IMPORT v;
  23.  
  24. (* Editor  *)
  25. FROM EditTypes  IMPORT EDITPTR, EDITOR, aLinePtr, aLineDesc, aLine, textPtr, bigTextPtr, 
  26.                        aMark, userProcType, userGetRectProc, drawUserProc, userCloseProc, 
  27.                        deskSize, pixOff, undoType, SuchFlags, SuchModus, searchDir, 
  28.                        searchPos, searchCount, CAT, CharSet, TrennSet, UmbruchSet,
  29.                        userKeyProc, userTopProc, userUntopProc, userPrePrintProc, 
  30.                        userListProc, theDrawLine, aBufferPtr, aBuffer, LFIRST, LNEXT,
  31.                        cursorHandle, maxBlocks;
  32.  
  33. IMPORT EditTypes;
  34.  
  35. FROM EditGlobals        IMPORT  ClipWork, GetTextWidth, AllocNew, GetQuote,
  36.                                 MouseArrow, MouseBusy, MouseHand,
  37.                                 HideMouse, ShowMouse, HideCursor, 
  38.                                 SaveMouse, RestoreMouse,
  39.                                 ShowCursor, ForceCursor, drawCursor, RowToIndex, 
  40.                                 SetDocument, CursorIsOn;
  41. FROM EditTools          IMPORT  SetInfoLine, SetEditTitle, ShowFileChanged, 
  42.                                 SetCurrLine, SetStartLine, getCharPos, 
  43.                                 SaveLine, SaveOp, DeleteLine, 
  44.                                 Undo, NewBlockToUndoBuffer,  
  45.                                 SetBlockstart, SetBlockend,
  46.                                 GetClickLineAndRow, TestBlockMarksAndSwap, ToWordEnd,
  47.                                 ToWordStart, ToLineStart, ToLineEnd, MarkLine, MarkBlock, 
  48.                                 ToBlockmark, SearchWord, ReplaceWord, FreeUndoBuffer;
  49.                                 
  50.                                 
  51. FROM EditDraw           IMPORT  drawLine, redrawLine, 
  52.                                 redrawLines, redrawWdw,
  53.                                 redrawLineArea, scrollRegion, CenterCurrline,
  54.                                 GetBlockRects, MarkArea; 
  55. IMPORT EditBase, EditFuncs, EditTools;
  56. IMPORT WdwManager;
  57. IMPORT ConfVars;
  58. IMPORT Varnames;
  59. IMPORT RectFuncs;
  60. IMPORT QuickSort;
  61.  
  62. IMPORT CatEdit;     (* zirkul„rer Import in IMPLEMENTATION *)
  63.  
  64. (*$? CAT:
  65. IMPORT Protokoll;
  66.  
  67. CONST   progName = 'CAT:';
  68. *)
  69. (*$? NOT CAT:
  70. IMPORT FredProtokoll;
  71.  
  72. CONST   progName = 'Fred:';
  73. *)
  74.  
  75.  
  76. CONST
  77.  
  78.         CR      = 15C;
  79.         LF      = 12C;
  80.         TAB     = 11C;
  81.  
  82.         emptyFile ='[2]['+progName+'|Die Datei ist leer!|Soll ein neuer Text|angelegt werden?][[Ja|:[Abbruch]';
  83.         newFile  = '[2]['+progName+'|Die Datei existiert nicht!|Soll ein neuer Text|angelegt werden?][[Ja|:[Abbruch]';
  84.         noBackup = '[3]['+progName+'|Backup konnte nicht|angelegt werden!][:[Abbruch]';
  85.         onlyMonoFont = '[3]['+progName+'|Block einrcken geht nur|mit unproportionalen|Zeichens„tzen!][[Ok]';
  86.         
  87.         saveAsTitle = 'Sichern als...'+0C;
  88.  
  89.         txtExt  = '*.*';
  90.         
  91.         cNoname = 'namenlos.txt';
  92.                        
  93.  
  94. PROCEDURE EditSaveWdwPos (wdw : INTEGER);
  95. (* Sichert die Position des Editors in den 
  96.  * Configvariablen
  97.  *)
  98.   VAR varName : ARRAY [0..255] OF CHAR;
  99.       full    : Rectangle;
  100.       ed      : EDITPTR;
  101. BEGIN
  102.   ed := EditFuncs.FindEditor (wdw);
  103.   IF ed # NIL
  104.   THEN 
  105.     WITH ed^ DO 
  106.       Strings.Concat (cEditWindow, StrConv.IntToStr (number, 0), varName, v.bool);
  107.       WdwManager.GetWdwSize (wdw, full);                    (* Gr”že des Fensters abfragen *)
  108.       v.bool := ConfVars.SetConfigRect (varName, full);
  109.       Strings.Concat (cEditFont, StrConv.IntToStr (number, 0), varName, v.bool);
  110.       v.bool := ConfVars.SetConfigInt (varName, font);
  111.       Strings.Concat (cEditSize, StrConv.IntToStr (number, 0), varName, v.bool);
  112.       v.bool := ConfVars.SetConfigInt (varName, fontSize);
  113.       Strings.Concat (cEditTabs, StrConv.IntToStr (number, 0), varName, v.bool);
  114.       v.bool := ConfVars.SetConfigBool (varName, realTabs);
  115.       Strings.Concat (cEditTabSize, StrConv.IntToStr (number, 0), varName, v.bool);
  116.       v.bool := ConfVars.SetConfigInt (varName, tabSize);;
  117.       Strings.Concat (cEditWrap, StrConv.IntToStr (number, 0), varName, v.bool);
  118.       v.bool := ConfVars.SetConfigBool (varName, umbruch);
  119.       Strings.Concat (cEditMargin, StrConv.IntToStr (number, 0), varName, v.bool);
  120.       v.bool := ConfVars.SetConfigInt (varName, rightMargin);
  121.       Strings.Concat (cEditInfo, StrConv.IntToStr (number, 0), varName, v.bool);
  122.       v.bool := ConfVars.SetConfigBool (varName, showInfo);
  123.       Strings.Concat (cEditZeile, StrConv.IntToStr (number, 0), varName, v.bool);
  124.       v.bool := ConfVars.SetConfigLongInt (varName, ed^.currLineNr);
  125.       Strings.Concat (cEditRow, StrConv.IntToStr (number, 0), varName, v.bool);
  126.       v.bool := ConfVars.SetConfigInt (varName, currRow);
  127.       Strings.Concat (cEditShowCr, StrConv.IntToStr (number, 0), varName, v.bool);
  128.       v.bool := ConfVars.SetConfigBool (varName, showCR);
  129.     END;
  130.   END;
  131. END EditSaveWdwPos;
  132.  
  133. PROCEDURE EditSavePos();
  134. (* Sichert die Position und den Inhalt aller offenen Editorfenster
  135.  * (nicht ReadOnly-Fenster) 
  136.  *)
  137.  VAR ed : EDITPTR;
  138.      varName : ARRAY [0..255] OF CHAR;
  139. BEGIN
  140.   ed := EditFuncs.editList;
  141.   WHILE ed # NIL DO
  142.     WITH ed^ DO
  143.       IF fileName.length > 0 
  144.       THEN
  145.         Strings.Concat (cEditFile, StrConv.IntToStr (number, 0), varName, v.bool);
  146.         v.bool := ConfVars.SetConfigString (varName, fileName.text^);
  147.         EditSaveWdwPos (wdw);
  148.       END;
  149.     END;
  150.     ed := ed^.nextEdit;
  151.   END;
  152. END EditSavePos;
  153.  
  154. (* Einfge- und L”schoperationen *)
  155.  
  156. PROCEDURE IndentBlock (wdw : INTEGER);
  157. VAR     index, i, t:            INTEGER;
  158.         Doit, Schirm:           BOOLEAN;
  159.         blank:                  ARRAY [0..80] OF CHAR;
  160.         ed:                     EDITPTR;
  161.         
  162.         Max:                    INTEGER; (* Maximale Zeilenl„nge fr Einrcken! *)
  163.  
  164.   PROCEDURE Ruecke (links: BOOLEAN);
  165.   VAR   l:              INTEGER;
  166.   BEGIN
  167.     WITH ed^ DO
  168.       ShowFileChanged(ed); (* Anzeigen, daž Text ge„ndert *)
  169.       IF index >= Max THEN RETURN END;
  170.       SetCurrLine (ed, blocks[0].blockStart.line);
  171.       REPEAT
  172.         (* YYYY Hier noch Anpassung auf CR/LF am Zeilenende einbauen! *)
  173.         l := editLen;
  174.         WHILE (l > 0) & ((editLine.text^[l-1] = CR) OR (editLine.text^[l-1] = LF)) DO DEC (l) END;
  175.         editChanged := TRUE;
  176.         IF (index  > l) & ~links THEN
  177.           AllocNew (editLine, index+4);
  178.           Strings.Insert (Strings.Space (index-l), l, editLine.text^, v.bool);
  179.           l := index;
  180.         END (* IF index *);
  181.         IF (l >= index) THEN
  182.           IF links THEN
  183.             Strings.Delete (editLine.text^, index, 1, v.bool);
  184.           ELSE
  185.             AllocNew (editLine, index+INTEGER((*SYSTEM.*)LENGTH (blank))+2);
  186.             Strings.Insert (blank, index, editLine.text^, v.bool);
  187.           END (* IF links oder rechts ruecken *);
  188.           l := (*SYSTEM.*)LENGTH (editLine.text^);
  189.           editLen := l;
  190.           v.bool := EditBase.PutLine (ed, currLineNr, editLine.text^, l);
  191.         END (* IF Laenge *);
  192.         IF currLineNr # blocks[0].blockEnd.line THEN
  193.           SetCurrLine (ed, currLineNr+1);
  194.         END (* IF *);
  195.       UNTIL (currLineNr = blocks[0].blockEnd.line);
  196.       SetCurrLine (ed, blocks[0].blockStart.line);
  197.       currRow := index;
  198.     END (* WITH ed *);
  199.   END Ruecke;
  200.   
  201.   VAR adr : RECORD a,b : ADDRESS; END;
  202.       taste, scan:      INTEGER;
  203.       ch:               CHAR;
  204.       key:              MOSGlobals.Key;
  205.       frame:            Rectangle;
  206.  
  207. BEGIN (* IndentBlock *)
  208.   ed := EditFuncs.FindEditor (wdw);
  209.   IF ed = NIL THEN RETURN END;
  210.   WITH ed^ DO 
  211.     IF ~block THEN RETURN END;
  212.     IF ~monoSpaced THEN MTE.info (onlyMonoFont); RETURN END;
  213.     (* Block sichern fr Undo *)
  214.     SaveOp (ed, blockPaste, FALSE); 
  215.     IF showInfo
  216.     THEN
  217.       (* Infozeile setzen *)
  218.       Strings.Assign (' Block einrcken (bei Cursor <-, ->), BS, Zeichen, RETURN fr Ende', WindowInfo, v.bool);
  219.       WdwManager.SetWdwInfoline (wdw, WindowInfo);
  220.     END;
  221.     (* Currline auf Blockanfang setzen *)
  222.     SetCurrLine (ed, blocks[0].blockStart.line);
  223.     currRow := blocks[0].blockStart.row;
  224.     CenterCurrline (ed);
  225.     (* Variablen initialisieren *)
  226.     blank [0] := ' '; blank [1] := 0C;
  227.     index := currRow;
  228.     Max := 512;
  229.     (* Menuzeile sperren und Window-Events verhindern *)
  230.     MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  231.     MagicAES.WindUpdate (MagicAES.BEGMCTRL);
  232.     HideMouse();
  233.     (* Cursor zeigen *)
  234.     HideCursor (ed);
  235.     blockIndent := TRUE;
  236.     ShowCursor (ed);
  237.     REPEAT
  238.       Doit := FALSE;
  239.       Schirm := FALSE;
  240.       MagicAES.EvntKeybd (taste, scan, ch);
  241.       Keyboard.GemCharToKey (taste, 0, key);
  242.       IF Keyboard.IsSpecial (key)
  243.       THEN
  244.         CASE Keyboard.SpecialKey (key) OF
  245.           tab:            t := tabSize * ((index DIV tabSize) + 1) - 1;
  246.                           FOR i := index TO t DO
  247.                             blank [i - index] := ' ';
  248.                           END;
  249.                           blank [t - index + 1] := 0C;
  250.                           IF realTabs THEN
  251.                             blank[0] := TAB;
  252.                             blank[1] := 0C;
  253.                           END;
  254.                           Ruecke (FALSE);
  255.                           HideCursor (ed);
  256.                           IF realTabs
  257.                           THEN
  258.                             INC (currRow);
  259.                           ELSE
  260.                             INC (currRow, t -index + 1);
  261.                           END;
  262.                           ShowCursor (ed);
  263.                           Doit := TRUE; Schirm := TRUE;
  264.                           index :=   currRow; |
  265.                           
  266.           left, 
  267.           wdLeft,
  268.           soln:          IF currRow > 0 THEN
  269.                             HideCursor (ed);
  270.                             DEC (currRow);
  271.                             ShowCursor (ed);
  272.                             Doit := TRUE;
  273.                             index := currRow;
  274.                           END (* IF *); |
  275.           backspace:      IF currRow > 0 THEN
  276.                             HideCursor (ed); DEC (currRow); ShowCursor (ed);
  277.                             Doit := TRUE; Schirm := TRUE;
  278.                             index := currRow;
  279.                             Ruecke (TRUE);
  280.                           END (* IF *); |
  281.           right, 
  282.           wdRight, 
  283.           eoln:           IF currRow < Max THEN
  284.                             HideCursor (ed);
  285.                             INC (currRow);
  286.                             ShowCursor (ed);
  287.                             Doit := TRUE;
  288.                             index := currRow;
  289.                           END (* IF *); |
  290.           delete:         Ruecke (TRUE); Doit := TRUE; Schirm := TRUE;|
  291.         ELSE
  292.         END; (* CASE *)
  293.       ELSIF Keyboard.IsASCII (key)
  294.       THEN
  295.         blank [0] := ch; blank [1] := 0C;
  296.         Ruecke (FALSE);
  297.         Doit := TRUE; Schirm := TRUE;
  298.         IF currRow < Max THEN
  299.           HideCursor (ed);
  300.           INC (currRow);
  301.           ShowCursor (ed);
  302.           index := currRow;
  303.         END (* IF *);
  304.       END (* IF *);
  305.       IF Doit THEN
  306.         CenterCurrline (ed);
  307.         ShowFileChanged(ed); (* Anzeigen, daž Text ge„ndert *)
  308.         IF Schirm THEN
  309.           (* Hier noch richtigen Redrawaufruf hinsetzen *)
  310.           redrawLineArea (ed, blocks[0].blockStart.line, blocks[0].blockEnd.line);
  311.         END (* IF Schirm *);
  312.       END (* IF Doit *);
  313.     UNTIL (Keyboard.IsSpecial (key) & (Keyboard.SpecialKey (key) = return));
  314.     (* Noch Blockstart fr Undobuffer merken *)
  315.     NewBlockToUndoBuffer (ed);
  316.     (* Cursor zeigen *)
  317.     HideCursor (ed);
  318.     blockIndent := FALSE;
  319.     (* Blockmarken noch l”schen *)
  320.     EditTools.ClearBlock (ed);
  321.     MagicAES.WindUpdate (MagicAES.ENDMCTRL);
  322.     MagicAES.WindUpdate (MagicAES.ENDUPDATE);
  323.     ShowCursor (ed);
  324.     ShowMouse(FALSE);
  325.     IF showInfo THEN SetInfoLine (ed); END;
  326.   END (* WITH ed^ *)
  327. END IndentBlock;
  328.  
  329.         (* Hilfsfunktionen fr OpenEditor und EditMerge *)
  330.         
  331. PROCEDURE getFileParms (REF path, FileName : ARRAY OF CHAR;
  332.                         new : BOOLEAN; alerts : BOOLEAN;
  333.                         VAR fn : aLineDesc; VAR flen : LONGCARD;
  334.                         VAR fHdl : INTEGER) : BOOLEAN;
  335.   VAR newName : ARRAY [0..139] OF CHAR;
  336.       newPath : ARRAY [0..139] OF CHAR;
  337. BEGIN
  338.   flen := 0;
  339.   fHdl := -1;
  340.   IF path[0] = 0C (* Pfad leer, aktuellen Pfad nehmen *)
  341.   THEN
  342.     (*$? NOT CAT: 
  343.     Directory.GetDefaultPath (newPath);
  344.     *)
  345.     (*$? CAT:
  346.     mtDir.GetPath (newPath);
  347.     *)
  348.   ELSE
  349.     Strings.Assign (path, newPath, v.bool);
  350.   END;
  351.   (* Dateinamen zusammenbauen *)
  352.   IF FileName[0] # 0C THEN 
  353.     fn.length := (*SYSTEM.*)LENGTH(newPath) + (*SYSTEM.*)LENGTH (FileName)+2;
  354.     ALLOCATE( fn.text, fn.length);
  355.     IF fn.text = NIL
  356.     THEN
  357.       (* not enough memory!! *)
  358.       EditFuncs.OutOfMem();
  359.       RETURN FALSE
  360.     END;
  361.     Strings.Concat (newPath, FileName, fn.text^, v.bool);
  362.   ELSE 
  363.     fn.length := 0;
  364.   END;
  365.     (* File ”ffnen *)
  366.     fHdl := MagicDOS.Fopen (fn.text^, {});
  367.     (*$? NOT CAT:
  368.     (* Suchen im Pfad *)
  369.     IF fHdl < 0 THEN
  370.       (* file nicht ge”ffnet *)
  371.       IF fHdl = MagicDOS.EFilNF
  372.       THEN
  373.         IF fn.length # 0
  374.         THEN
  375.           Paths.SearchFile (FileName, ShellMsg.SrcPaths, Paths.fromStart, v.bool, newName);
  376.           IF v.bool
  377.           THEN
  378.             DEALLOCATE (fn.text, 0);
  379.             ALLOCATE (fn.text, (*SYSTEM.*)LENGTH (newName)+2);
  380.             IF fn.text = NIL THEN HALT END;
  381.             Strings.Assign (newName, fn.text^, v.bool);
  382.             fHdl := MagicDOS.Fopen (fn.text^, {});
  383.           END;
  384.         END;
  385.       END;
  386.     END;
  387.     *)
  388.     IF fHdl < 0 THEN
  389.       IF fHdl = MagicDOS.EFilNF THEN
  390.         IF alerts & ~new THEN 
  391.           v.int := mtAlerts.Alert (1,newFile);
  392.           IF v.int = 2
  393.           THEN 
  394.             RETURN FALSE
  395.           ELSE
  396.             RETURN TRUE
  397.           END;
  398.         ELSE
  399.           RETURN TRUE;
  400.         END;
  401.       ELSE
  402.         fn.length := 0;
  403.         DEALLOCATE (fn.text, 0);
  404.         fn.text := NIL;
  405.         IF alerts THEN CatFiles.ErrorAlert (fHdl); END;
  406.         RETURN FALSE
  407.       END;
  408.     END;
  409.     (* Filegr”že feststellen *)
  410.     flen := MagicDOS.Fseek (0, fHdl, MagicDOS.SeekEnd);
  411.     v.lcard  := MagicDOS.Fseek (0, fHdl, MagicDOS.SeekStart);
  412.     IF (flen = 0) & ~new
  413.     THEN
  414.       (* Lohnt sich nicht :-) *)
  415.       v.int := mtAlerts.Alert (1,emptyFile);
  416.       IF v.int = 2
  417.       THEN
  418.         (* Abbruch gew„hlt *)
  419.         RETURN FALSE
  420.       END;
  421.     END;
  422.   RETURN TRUE;
  423. END getFileParms;
  424.  
  425. PROCEDURE testMem (flen : LONGCARD; VAR memSize : LONGCARD;
  426.                    VAR fastRead : BOOLEAN) : BOOLEAN;
  427. BEGIN
  428.   (* freien Speicher feststellen, mindestens 30 kB frei! *)
  429.   memSize := flen;
  430.   memSize := Storage.MemAvail();
  431.   IF memSize < (2 * flen + ((flen DIV 100) * 115) + 4096L)
  432.   THEN
  433.     IF memSize < (flen DIV 100) * 115 + 4096L
  434.     THEN 
  435.       (* not enough memory, just don't try any more *)
  436.       EditFuncs.OutOfMem();
  437.       RETURN FALSE
  438.     ELSE
  439.       (* k”nnte klappen, versuchen wir mal die langsame Methode! *)
  440.       fastRead := FALSE;
  441.     END;
  442.   ELSE
  443.     fastRead := TRUE;
  444.   END;
  445.   RETURN TRUE;
  446. END testMem;
  447.  
  448. PROCEDURE getReadBuff (memSize, flen : LONGCARD; VAR readBuf : ADDRESS) : BOOLEAN;
  449.   VAR voidBuf : ADDRESS;
  450.       bufSize : LONGCARD;
  451. BEGIN
  452.   (* 2 * Max(TextSize, 10 kB) allozieren *)
  453.   memSize := Storage.MemAvail();
  454.   IF memSize > 4 * flen 
  455.   THEN
  456.     (* wir haben VIEL Speicher *)
  457.     IF memSize > flen + 32000
  458.     THEN
  459.       bufSize := BinOps.HigherLCard (memSize-flen-32000, 10*1024);
  460.     ELSE
  461.       bufSize := 10*1024
  462.     END;
  463.   ELSE
  464.     bufSize := BinOps.HigherLCard ( (flen DIV 100) * 115 + 8192L, 10*1024);
  465.     IF memSize > flen + 32000
  466.     THEN
  467.       bufSize := BinOps.LowerLCard (bufSize, memSize-flen-32000);
  468.     END;
  469.   END;
  470.   ALLOCATE (voidBuf, bufSize);
  471.   IF (voidBuf = NIL) THEN
  472.     (* Not enough memory *)
  473.     (* melden *)
  474.     EditFuncs.OutOfMem();
  475.     RETURN FALSE
  476.   END;
  477.   ALLOCATE (readBuf, flen+2);
  478.   IF readBuf = NIL THEN
  479.     (* Not enough memory *)
  480.     EditFuncs.OutOfMem();
  481.     DEALLOCATE (voidBuf, 0);
  482.     RETURN FALSE
  483.   END;
  484.   (* 1 Buffer wieder freigeben *)
  485.   DEALLOCATE (voidBuf, 0);
  486.   RETURN TRUE
  487. END getReadBuff;
  488.  
  489. PROCEDURE EditPasteFile (wdw: INTEGER; isFilter: BOOLEAN; REF path, name: ARRAY OF CHAR);
  490. (* Fgt einen Text mit Filename ein 
  491.  *)
  492. VAR  flen       : LONGCARD;
  493.      memSize    : LONGCARD;
  494.      ed         : EDITPTR;
  495.      readBuf    : POINTER TO ARRAY [0L..$FFFFFFFF] OF CHAR;
  496.      bufSize    : LONGCARD;
  497.      fastRead   : BOOLEAN;
  498.      fn         : aLineDesc;
  499.      fHdl       : INTEGER;
  500.      scrLine    : INTEGER;
  501.      wasBlock   : BOOLEAN;
  502.      inLine     : BOOLEAN;
  503.  
  504.   PROCEDURE FreeStuff();
  505.   (* Dealloziert allozierte Pointer und gibt sonstiges Zeugs frei
  506.    *)
  507.   BEGIN
  508.     IF readBuf # NIL THEN DEALLOCATE (readBuf, 0) END;
  509.     IF fHdl > 0  THEN v.int := MagicDOS.Fclose (fHdl); CatFiles.ErrorAlert (v.int) END;
  510.     IF fn.text # NIL THEN DEALLOCATE (fn.text, 0) END;
  511.   END FreeStuff;
  512.  
  513. BEGIN
  514.   ed := EditFuncs.FindEditor (wdw);
  515.   IF ed # NIL
  516.   THEN
  517.     readBuf := NIL;
  518.     IF ed^.readOnly & ~isFilter THEN RETURN END;
  519.     IF getFileParms (path, name, TRUE, FALSE, fn, flen, fHdl) & (flen > 0)
  520.     THEN
  521.       (* HideMouse ();
  522.       HideCursor (ed); *)
  523.       WITH ed^ DO
  524.         scrLine := SHORT(ed^.currLineNr - ed^.StartLine);
  525.         DEALLOCATE (fn.text, 0);
  526.         v.int := MagicDOS.Fclose (fHdl);
  527.         IF flen > 0 
  528.         THEN
  529.           wasBlock := ed^.block;
  530.           IF ed^.block THEN 
  531.             SaveOp (ed, blockPaste, FALSE); 
  532.             v.bool := EditFuncs.cutBlock (ed, FALSE, FALSE); 
  533.             blocks[0].blockStart.line := currLineNr;
  534.             blocks[0].blockStart.row := currRow;
  535.             block := TRUE; 
  536.           ELSE
  537.             SetBlockstart (ed);
  538.             SaveOp (ed, normalPaste, FALSE);
  539.             block := TRUE;
  540.           END;
  541.           inLine := currRow # 0;
  542.           IF NOT ( (* Dateinamen basteln, Datei ”ffnen und L„nge feststellen *)
  543.                    getFileParms (path, name, FALSE, FALSE, fn, flen, fHdl) & 
  544.                    (* Speicher feststellen und auf flen testen *)
  545.                    testMem(flen, memSize, fastRead) & 
  546.                    (* Lesebuffer allozieren *)
  547.                    getReadBuff (memSize, flen, readBuf) & 
  548.                    (* Text einlesen und einfgen *)
  549.                    EditFuncs.readText (ed, fastRead, flen, fHdl, ed^.rightMargin, readBuf, ~inLine, FALSE)
  550.                  )
  551.           THEN
  552.             FreeStuff;
  553.             (*
  554.             ShowCursor (ed);
  555.             ShowMouse (FALSE);
  556.             *)
  557.             RETURN
  558.           END;
  559.           HideMouse ();
  560.           HideCursor (ed);
  561.           EditTools.UpdateCurrLine (ed, currLineNr);
  562.           ShowFileChanged (ed); 
  563.           IF fn.text # NIL THEN DEALLOCATE (fn.text, 0) END;
  564.           NewBlockToUndoBuffer (ed);
  565.           (* Jetzt Cursorposition anpassen an Ende des gepasteten Stcks 
  566.            *)
  567.           SetCurrLine (ed, blocks[0].blockEnd.line);
  568.           currRow := blocks[0].blockEnd.row;
  569.           SetDocument (ed);
  570.           IF ~wasBlock THEN 
  571.             (* normal Paste *) 
  572.             block := FALSE; 
  573.             blocks[0].blockStart.line := -1; 
  574.             blocks[0].blockEnd.line := -1; 
  575.           END;
  576.           WdwManager.RedrawWdw (wdw, editWork);
  577.           CenterCurrline (ed);
  578.           IF showInfo THEN SetInfoLine (ed) END;
  579.           ShowCursor (ed);
  580.           ShowMouse (FALSE);
  581.         END;
  582.       END; (* WITH ed^ *)
  583.     END;
  584.   END;    
  585. END EditPasteFile;
  586.  
  587. PROCEDURE SaveText (VAR ed : EDITPTR; saveas : BOOLEAN; takeName: BOOLEAN; REF fpath, fname : ARRAY OF CHAR) : BOOLEAN;
  588.   
  589.   VAR line : aLinePtr;
  590.       path : ARRAY [0..130] OF CHAR;
  591.       name : ARRAY [0..12] OF CHAR;
  592.       fullName : ARRAY [0..145] OF CHAR;
  593.       fHdl : INTEGER;
  594.       len   : LONGCARD;
  595.       isOpen: BOOLEAN;
  596.       appended : BOOLEAN;
  597.       i     : INTEGER;
  598. BEGIN
  599.   isOpen := FALSE;
  600.   appended := FALSE;
  601.   WITH ed^ DO
  602.     IF editChanged THEN
  603.       v.bool := EditBase.PutCurrLine (ed);
  604.     END;
  605.     IF new & ~saveas
  606.     THEN
  607.       IF fileName.length = 0
  608.       THEN
  609.         (*$? NOT CAT: 
  610.         Directory.GetDefaultPath (path);
  611.         *)
  612.         (*$? CAT:
  613.         mtDir.GetPath (path);
  614.         *)
  615.         Strings.Assign (cNoname,name, v.bool);
  616.         IF CatGlobal.FselGet (path, name, txtExt, saveAsTitle, FALSE)
  617.         THEN
  618.           Strings.Concat (path, name, fullName, v.bool);
  619.           fHdl := MagicDOS.Fopen (fullName, {MagicDOS.Write});
  620.           IF fHdl # MagicDOS.EFilNF
  621.           THEN 
  622.             IF fHdl > MagicDOS.EOK
  623.             THEN
  624.               v.int := mtAlerts.Alert (2,MTE.Overwrite);
  625.               IF v.int = 2 THEN 
  626.                 len := MagicDOS.Fseek (0, fHdl, MagicDOS.SeekEnd); 
  627.                 appended := TRUE;
  628.               ELSIF v.int = 3 THEN 
  629.                 v.int := MagicDOS.Fclose (fHdl); 
  630.                 CatFiles.ErrorAlert (v.int);
  631.                 RETURN FALSE 
  632.               ELSE
  633.                 (* Schliežen und Fcreate machen *)
  634.                 v.int := MagicDOS.Fclose (fHdl);
  635.                 fHdl := MagicDOS.Fcreate (fullName, {});
  636.                 IF fHdl < MagicDOS.EOK
  637.                 THEN
  638.                   CatFiles.ErrorAlert (fHdl);
  639.                   RETURN FALSE;
  640.                 END;
  641.               END;
  642.               appended := v.int = 2;
  643.             ELSE
  644.               CatFiles.ErrorAlert (fHdl);
  645.               RETURN FALSE
  646.             END;
  647.           ELSE (* IF fHdl # EFilNF *)
  648.             (* File not found: Create *)
  649.             fHdl := MagicDOS.Fcreate (fullName, {});
  650.             IF fHdl < MagicDOS.EOK
  651.             THEN
  652.               CatFiles.ErrorAlert (fHdl);
  653.               RETURN FALSE
  654.             END;
  655.           END; (* IF fHdl # EFilNF *)
  656.         ELSE
  657.           RETURN FALSE
  658.         END; (* IF FselGet *)
  659.         isOpen := TRUE;
  660.       END (* IF fileName.length = 0 *);
  661.     END (* IF new *);
  662.     IF ~isOpen 
  663.     THEN
  664.       IF (fname[0] # "")
  665.       THEN
  666.         Strings.Concat (fpath, fname, fullName, v.bool);
  667.       ELSE
  668.         Strings.Assign (fileName.text^, fullName, v.bool);
  669.       END;
  670.       fHdl := MagicDOS.Fopen (fullName, {MagicDOS.Write});
  671.       IF (fHdl < MagicDOS.EOK) THEN
  672.         IF (fHdl = MagicDOS.EFilNF) THEN
  673.           fHdl := MagicDOS.Fcreate (fullName, {});
  674.           IF fHdl < MagicDOS.EOK THEN 
  675.             CatFiles.ErrorAlert (fHdl);
  676.             RETURN FALSE
  677.           END;
  678.         ELSE
  679.           CatFiles.ErrorAlert (fHdl);
  680.           RETURN FALSE
  681.         END;
  682.       ELSE
  683.         IF saveas
  684.         THEN
  685.           v.int := mtAlerts.Alert (2,MTE.Overwrite);
  686.           IF v.int = 2 THEN 
  687.             (* Anh„ngen *)
  688.             len := MagicDOS.Fseek (0, fHdl, MagicDOS.SeekEnd); 
  689.             appended := TRUE;
  690.           ELSIF v.int = 3 THEN 
  691.             (* Abbruch *)
  692.             v.int := MagicDOS.Fclose (fHdl); 
  693.             CatFiles.ErrorAlert (v.int);
  694.             RETURN FALSE 
  695.           ELSE (* v.int = 1 *)
  696.             (* šberschreiben *)
  697.             (* Schliežen und Fcreate machen *)
  698.             v.int := MagicDOS.Fclose (fHdl);
  699.             fHdl := MagicDOS.Fcreate (fullName, {});
  700.             IF fHdl < MagicDOS.EOK
  701.             THEN
  702.               CatFiles.ErrorAlert (fHdl);
  703.               RETURN FALSE;
  704.             END;
  705.           END;
  706.         ELSE
  707.           (* Direkt berschreiben *)
  708.           (* Schliežen und Fcreate machen *)
  709.           v.int := MagicDOS.Fclose (fHdl);
  710.           (*$? NOT CAT:
  711.           IF backup THEN
  712.             IF ~CatGlobal.CreateBackup (fullName)
  713.             THEN
  714.               v.int := mtAlerts.Alert (1,noBackup);
  715.               RETURN FALSE
  716.             END;
  717.           END;
  718.           *)
  719.           fHdl := MagicDOS.Fcreate (fullName, {});
  720.           IF fHdl < MagicDOS.EOK
  721.           THEN
  722.             CatFiles.ErrorAlert (fHdl);
  723.             RETURN FALSE;
  724.           END;
  725.         END;
  726.       END; 
  727.     END (* IF ~isOpen *);
  728.     (* So, jetzt ist garantiert ein File offen, wir k”nnen endlich schreiben *)
  729.     IF block & saveas
  730.     THEN
  731.       FOR i := 0 TO maxBlocks - 1 DO
  732.         WITH blocks[i] DO
  733.           IF (blockStart.line >= 0) & (blockEnd.line >= 0)
  734.           THEN
  735.             v.bool := EditFuncs.outputText (ed, blockStart.line, blockStart.row,
  736.                                             blockEnd.line, blockEnd.row, fHdl, umbruch, FALSE);
  737.           END;
  738.         END;
  739.       END;
  740.     ELSE
  741.       v.bool := EditFuncs.outputText (ed, 0, 0, -1, -1, fHdl, umbruch, FALSE);
  742.     END;
  743.     v.int := MagicDOS.Fclose (fHdl);
  744.     CatFiles.ErrorAlert (v.int);
  745.     IF v.int # MagicDOS.EOK THEN RETURN FALSE 
  746.     ELSE
  747.       IF (takeName & ((saveas & ~block & (fname[0] # "")) OR (new & ~block)) & ~appended & ~readOnly)
  748.       THEN
  749.         (* hier noch Assign auf Filename *)
  750.         fileName.length := (*SYSTEM.*)LENGTH(fullName) + 1;
  751.         IF fileName.text # NIL THEN DEALLOCATE (fileName.text, 0); END;
  752.         ALLOCATE (fileName.text, fileName.length);
  753.         IF fileName.text = NIL
  754.         THEN
  755.           (* not enough memory!! *)
  756.           EditFuncs.OutOfMem();
  757.           RETURN FALSE
  758.         END;
  759.         Strings.Assign (fullName, fileName.text^, v.bool);
  760.       END;
  761.       IF ~(block & saveas)
  762.       THEN
  763.         changed := FALSE;
  764.       END;
  765.     END;
  766.     SetEditTitle (ed);
  767.     (*$? CAT: 
  768.     Protokoll.SendPathUpdate (fullName);
  769.     *)
  770.     (*$? NOT CAT:
  771.     FredProtokoll.SendPathUpdate (fullName);
  772.     *)
  773.   END (* WITH ed DO *);
  774.   RETURN TRUE;
  775. END SaveText;
  776.  
  777. PROCEDURE PerformDragDrop (ed : EDITPTR; x, y: INTEGER; kstate, buts: BITSET);
  778.   VAR outline: ARRAY [0..maxBlocks - 1] OF ARRAY [0..20] OF Point;
  779.       outRects: ARRAY [0..maxBlocks - 1 ] OF ARRAY [0..3] OF Rectangle;
  780.       count   : INTEGER;
  781.       pIdx    : ARRAY [0..maxBlocks-1] OF INTEGER;
  782.       i : INTEGER;
  783.       deltaX,
  784.       deltaY,
  785.       oldX,
  786.       oldY : INTEGER;
  787.       style: CARDINAL;
  788.       bl   : INTEGER;
  789. BEGIN
  790.   WITH ed^ DO
  791.     (* get block rectangles *)
  792.     FOR bl := 0 TO maxBlocks - 1 DO
  793.       IF (blocks[bl].blockStart.line >= 0) & (blocks[bl].blockEnd.line >= 0)
  794.       THEN
  795.         GetBlockRects (ed, outRects[bl], count, blocks[bl].blockStart.line, blocks[bl].blockStart.row, blocks[bl].blockEnd.line, blocks[bl].blockEnd.row);
  796.       ELSE
  797.         count := 0
  798.       END;
  799.       (* now calculate outline points of rectangles *)
  800.       pIdx[bl] := 0;
  801.       IF count > 0
  802.       THEN 
  803.         outline[bl][pIdx[bl]].x := outRects[bl][0].x;
  804.         outline[bl][pIdx[bl]].y := outRects[bl][0].y;
  805.         INC (pIdx[bl]);
  806.         outline[bl][pIdx[bl]].x := outRects[bl][0].w+1;
  807.         outline[bl][pIdx[bl]].y := outRects[bl][0].y;
  808.         INC (pIdx[bl]);
  809.         outline[bl][pIdx[bl]].x := outRects[bl][0].w+1;
  810.         outline[bl][pIdx[bl]].y := outRects[bl][0].h+1;
  811.         INC (pIdx[bl]);
  812.         (* walk down right edge *)
  813.         FOR i := 1 TO count - 1 DO 
  814.           outline[bl][pIdx[bl]].x := outRects[bl][i].w+1;
  815.           outline[bl][pIdx[bl]].y := outRects[bl][i].y;
  816.           INC (pIdx[bl]);
  817.           outline[bl][pIdx[bl]].x := outRects[bl][i].w+1;
  818.           outline[bl][pIdx[bl]].y := outRects[bl][i].h+1;
  819.           INC (pIdx[bl]);
  820.         END;
  821.         (* Jetzt rckw„rts die linke Kante hoch *)
  822.         FOR i := count - 1 TO 0 BY -1 DO
  823.           outline[bl][pIdx[bl]].x := outRects[bl][i].x;
  824.           outline[bl][pIdx[bl]].y := outRects[bl][i].h+1;
  825.           INC (pIdx[bl]);
  826.           outline[bl][pIdx[bl]].x := outRects[bl][i].x;
  827.           outline[bl][pIdx[bl]].y := outRects[bl][i].y;
  828.           INC (pIdx[bl]);
  829.         END;
  830.       END;
  831.     END;
  832.     (* Jetzt haben wir eine Outline, da sind zwar m”glicherweise doppelte 
  833.      * Punkte drin, aber das ist egal 
  834.      *)
  835.     oldX := x; 
  836.     oldY := y;
  837.     MagicAES.WindUpdate (MagicAES.BEGMCTRL);
  838.     ShowMouse(FALSE);
  839.     MouseHand();
  840.     (* Writemode auf XOR setzen *)
  841.     v.int := MagicVDI.SetWritemode (hdl, MagicVDI.XOR);
  842.     (* Linestyle etc. setzen *)
  843.     v.int := MagicVDI.SetLinetype (hdl, MagicVDI.User);
  844.     IF ODD (x)
  845.     THEN
  846.       style := $AAAA;
  847.     ELSE
  848.       style := $5555;
  849.     END;
  850.     MagicVDI.SetUserlinestyle (hdl, style);
  851.     v.int := MagicVDI.SetLinewidth (hdl, 1);
  852.     v.int := MagicVDI.SetLinecolor (hdl, 1);
  853.     (* Clipping setzen *)
  854.     WdwManager.SetClip (hdl, WdwManager.deskSize, TRUE);
  855.     (* Linie zeichnen *)
  856.     HideMouse();
  857.     FOR bl := 0 TO maxBlocks - 1 DO 
  858.       IF pIdx[bl] > 0
  859.       THEN
  860.         MagicVDI.Polyline (hdl, pIdx[bl], outline[bl]);
  861.       END;
  862.     END;
  863.     ShowMouse(FALSE);
  864.     REPEAT
  865.       MagicAES.GrafMkstate (x, y, buts, kstate);
  866.       IF (x # oldX) OR (y # oldY)
  867.       THEN 
  868.         HideMouse();
  869.         FOR bl := 0 TO maxBlocks - 1 DO 
  870.           IF pIdx[bl] > 0
  871.           THEN
  872.             (* Linie wieder wegzeichnen an alten Koordinaten *)
  873.             MagicVDI.Polyline (hdl, pIdx[bl], outline[bl]);
  874.             (* Koordinaten anpassen *)
  875.             deltaX := x - oldX;
  876.             deltaY := y - oldY;
  877.             FOR i := 0 TO pIdx[bl] - 1 DO 
  878.               INC (outline[bl][i].x, deltaX);
  879.               INC (outline[bl][i].y, deltaY);
  880.             END;
  881.             (* Neue Outline zeichnen *)
  882.             MagicVDI.Polyline (hdl, pIdx[bl], outline[bl]);
  883.           END;
  884.         END;
  885.         ShowMouse(FALSE);
  886.         oldX := x;
  887.         oldY := y;
  888.       END;
  889.     UNTIL ~(0 IN buts);
  890.     (* Outline wieder wegzeichnen *)
  891.     HideMouse();
  892.     FOR bl := 0 TO maxBlocks - 1 DO 
  893.       IF pIdx[bl] > 0
  894.       THEN
  895.         MagicVDI.Polyline (hdl, pIdx[bl], outline[bl]);
  896.       END;
  897.     END;
  898.     ShowMouse(FALSE);
  899.     (* Writemode zurcksetzen *)
  900.     v.int := MagicVDI.SetWritemode (hdl, MagicVDI.REPLACE);
  901.     (* Clipping auf Workbereich setzen *)
  902.     ClipWork (ed);
  903.     MagicAES.WindUpdate (MagicAES.ENDMCTRL);
  904.     (* Drag und Drop ausfhren *)
  905.     MagicAES.WindUpdate (MagicAES.ENDUPDATE);
  906.     v.bool := WdwManager.WdwDDServe (wdw, x, y, kstate);
  907.     MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  908.     (* Mauszeiger zurcksetzen *)
  909.     MouseArrow();
  910.     HideMouse();
  911.   END;
  912. END PerformDragDrop;
  913.  
  914. PROCEDURE ClickIsInBlock (wdw : INTEGER; x, y: INTEGER) : BOOLEAN;
  915. (* Gibt zurck, ob die Position x, y im Blockbereich liegt
  916.  *)
  917.   VAR ed : EDITPTR;
  918.       clLine    : LONGINT;
  919.       clRow     : INTEGER;
  920.       oLine     : LONGINT;
  921.       oRow      : INTEGER;
  922. BEGIN
  923.   IF ~CatEdit.BlockIsMarked (wdw) THEN RETURN FALSE END;
  924.   ed := EditFuncs.FindEditor (wdw);
  925.   IF ed # NIL
  926.   THEN
  927.     WITH ed^ DO
  928.       oRow := currRow;
  929.       oLine := currLineNr;
  930.       IF RectFuncs.IsInRect (x, y, editWork)
  931.       THEN
  932.         GetClickLineAndRow (ed, x, y, clLine, clRow);
  933.         SetCurrLine (ed, oLine);
  934.         currRow := oRow;
  935.         WITH blocks[0] DO
  936.           IF ( (clLine > blockStart.line) OR 
  937.                ((clLine = blockStart.line) & (clRow >= blockStart.row)) ) & 
  938.              ( (clLine < blockEnd.line) OR
  939.                ((clLine = blockEnd.line) & (clRow <= blockEnd.row)) )
  940.           THEN 
  941.             RETURN TRUE
  942.           END;
  943.         END;
  944.       END;
  945.     END;
  946.   END;
  947.   RETURN FALSE;
  948. END ClickIsInBlock;
  949.  
  950. PROCEDURE CheckWildAssign (VAR search, repl: ARRAY OF CHAR): BOOLEAN;
  951. (* Prft die Konsistenz von Wildcards und ihren Gegenstcken im Such-
  952.  * und Ersetzstring
  953.  *)
  954.  VAR one, all : CHAR;
  955.      numC     : CHAR;
  956.      i        : INTEGER;
  957.      oneC,
  958.      allC     : CARDINAL;
  959.      M        : INTEGER;
  960. BEGIN
  961.   one := EditTypes.wildOneChar;
  962.   all := EditTypes.wildAllChar;
  963.  
  964.   M := (*SYSTEM.*)LENGTH (search); (* Anzahl der Zeichen im Suchstring *)
  965.  
  966.   (* Jetzt erstmal alle Wildcardzeichen am Anfang und am Ende l”schen,
  967.    * die sind berflssig
  968.    *)
  969.   
  970.   WHILE ((search [0] = one) 
  971.          OR (search [0] = all)) DO
  972.     Strings.Delete (search, 0, 1, v.bool);
  973.   END;
  974.   M := (*SYSTEM.*)LENGTH (search); (* Anzahl der Zeichen im Suchstring *)
  975.   WHILE (M > 1) & ((search[M-1] = all) OR (search[M-1] = one)) DO
  976.     search[M-1] := 0c; DEC (M);
  977.   END;
  978.  
  979.   oneC := 0;
  980.   i := 0;
  981.   LOOP
  982.     i := Strings.Pos (one, search, i);
  983.     IF i >= 0 THEN INC (oneC); INC (i) 
  984.     ELSE
  985.       EXIT
  986.     END;
  987.   END;
  988.   allC := 0;
  989.   i := 0;
  990.   LOOP
  991.     i := Strings.Pos (all, search, i);
  992.     IF i >= 0 THEN INC (allC); INC (i) 
  993.     ELSE
  994.       EXIT
  995.     END;
  996.   END;
  997.   (* Jetzt haben wir die Anzahl der Wildcards im Suchstring *)
  998.   IF (oneC > 10) OR (allC > 10) THEN RETURN FALSE END;
  999.   (* Jetzt den Ersetzstring prfen *)
  1000.   i := 0;
  1001.   LOOP
  1002.     i := Strings.Pos (one, repl, i);
  1003.     IF i >= 0 THEN 
  1004.       (* N„chstes Zeichen testen, ob es eine Nummer ist *)
  1005.       numC := repl[i+1];
  1006.       IF (numC >= '0') & (numC <= '9')
  1007.       THEN
  1008.         IF (ORD (numC) - ORD ('0')) >= oneC
  1009.         THEN 
  1010.           RETURN FALSE
  1011.         END;
  1012.       END;
  1013.       INC (i);
  1014.     ELSE
  1015.       EXIT
  1016.     END;
  1017.   END;
  1018.   i := 0;
  1019.   LOOP
  1020.     i := Strings.Pos (all, repl, i);
  1021.     IF i >= 0 THEN 
  1022.       (* N„chstes Zeichen testen, ob es eine Nummer ist *)
  1023.       numC := repl[i+1];
  1024.       IF (numC >= '0') & (numC <= '9')
  1025.       THEN
  1026.         IF (ORD (numC) - ORD ('0')) >= allC
  1027.         THEN 
  1028.           RETURN FALSE
  1029.         END;
  1030.       END;
  1031.       INC (i);
  1032.     ELSE
  1033.       EXIT
  1034.     END;
  1035.   END;
  1036.   RETURN TRUE;
  1037. END CheckWildAssign;
  1038.  
  1039. PROCEDURE MarkMultiple (ed: EDITPTR);
  1040. VAR     index, i, t:            INTEGER;
  1041.         Doit, Schirm:           BOOLEAN;
  1042.         blank:                  ARRAY [0..80] OF CHAR;
  1043.         
  1044.         Max:                    INTEGER; (* Maximale Zeilenl„nge fr Einrcken! *)
  1045.  
  1046. PROCEDURE DoEvent (VAR scan, char: CHAR; VAR taste: INTEGER; VAR kstate: BITSET);
  1047.  
  1048. VAR mBuff: ARRAY [0..15] OF INTEGER;
  1049.     dr   : RECORD
  1050.              CASE :BOOLEAN OF
  1051.                TRUE : x,y,w,h : INTEGER|
  1052.                FALSE: adr, dum: ADDRESS
  1053.              END
  1054.            END;
  1055.     evnt      : BITSET;
  1056.     doExit    : BOOLEAN;
  1057.     moX, moY  : INTEGER;
  1058.     moButton  : BITSET;
  1059.     bReturn   : INTEGER;
  1060.     sc        : INTEGER;
  1061. BEGIN
  1062.   evnt := MagicAES.EvntMulti({MagicAES.MUKEYBD}, 0,{},{}, 0,dr, 0, 
  1063.                              dr, mBuff, 0, 0, moX, moY, moButton, taste, kstate, sc, char, bReturn);
  1064.   scan := CHAR(SHORT(sc));
  1065. END DoEvent;
  1066.  
  1067.   CONST maxMarks = (maxBlocks - 1) * 2 - 1;
  1068.   
  1069.   VAR adr       : RECORD a,b : ADDRESS; END;
  1070.       taste     : INTEGER;
  1071.       scan, ch  : CHAR;
  1072.       kstate    : BITSET;
  1073.       key       : MOSGlobals.Key;
  1074.       frame     : Rectangle;
  1075.       oldLine   : LONGINT;
  1076.       oldRow    : INTEGER;
  1077.       marked    : BOOLEAN;
  1078.       wasMarked : BOOLEAN;
  1079.       ctrl      : BOOLEAN;
  1080.       lastMark  : INTEGER;
  1081.       highMark  : INTEGER;
  1082.       marks,    
  1083.       markSort  : ARRAY [0..maxMarks] OF aMark;
  1084.       
  1085. PROCEDURE SortMark (a1, a2: ADDRESS): BOOLEAN;
  1086.   VAR m1, m2: POINTER TO aMark;
  1087. BEGIN
  1088.   m1 := a1;
  1089.   m2 := a2;
  1090.   IF m1^.line < 0
  1091.   THEN
  1092.     RETURN FALSE;
  1093.   END;
  1094.   RETURN (m1^.line < m2^.line) OR 
  1095.          ((m1^.line = m2^.line) &  (m1^.row < m2^.row));
  1096. END SortMark;
  1097.  
  1098. PROCEDURE RemoveTwoMarks(REF which: aMark);
  1099.   VAR i, k : INTEGER;
  1100.       rmvCount : INTEGER;
  1101. BEGIN
  1102.   i := 0;
  1103.   rmvCount := 0;
  1104.   WHILE (i <= highMark) & (rmvCount < 2) DO
  1105.     IF (which.line = marks[i].line) 
  1106.      & (which.row  = marks[i].row) 
  1107.     THEN
  1108.       IF i = lastMark
  1109.       THEN
  1110.         INC (i);
  1111.       ELSE 
  1112.         (* marks[i] entfernen *)
  1113.         FOR k := i TO highMark-1 DO
  1114.           marks[k] := marks[k+1];
  1115.         END;
  1116.         DEC (highMark);
  1117.         IF lastMark > i
  1118.         THEN
  1119.           DEC (lastMark);
  1120.         END;
  1121.         INC (rmvCount);
  1122.       END;
  1123.     ELSE
  1124.       INC (i);
  1125.     END;
  1126.   END; 
  1127. END RemoveTwoMarks;
  1128.  
  1129. PROCEDURE MarkToBlocks();
  1130.   VAR i : INTEGER;
  1131.       high : INTEGER;
  1132. BEGIN
  1133.   IF ODD (highMark)
  1134.   THEN 
  1135.     high := highMark
  1136.   ELSE
  1137.     high := highMark - 1
  1138.   END;
  1139.   markSort := marks;
  1140.   v.bool := QuickSort.sortIt (0, high, markSort, SortMark, TSIZE (aMark), QuickSort.noBreak);
  1141.   FOR i := 0 TO maxBlocks-1 DO
  1142.     ed^.blocks[i].blockStart.line := -1;
  1143.     ed^.blocks[i].blockEnd.line := -1;
  1144.   END;
  1145.   FOR i := 0 TO high BY 2 DO
  1146.     IF (markSort[i].line # markSort[i+1].line)
  1147.     OR (markSort[i].row  # markSort[i+1].row)
  1148.     THEN
  1149.       ed^.blocks[i DIV 2].blockStart := markSort[i];
  1150.       ed^.blocks[i DIV 2].blockEnd   := markSort[i+1];
  1151.       ed^.multiBlockIdx := i DIV 2;
  1152.     ELSE
  1153.       RemoveTwoMarks(markSort[i]);
  1154.     END;
  1155.   END;
  1156. END MarkToBlocks;
  1157.  
  1158. BEGIN (* MarkMultiple *)
  1159.   IF ed = NIL THEN RETURN END;
  1160.   WITH ed^ DO 
  1161.     (* vorhandene Blockmarkierung l”schen *)
  1162.     EditTools.ClearBlock (ed);
  1163.     block := FALSE;
  1164.     multiBlockIdx := 0;
  1165.     lastMark := 0;
  1166.     highMark := 0;
  1167.     CenterCurrline (ed);
  1168.     (* Variablen initialisieren *)
  1169.     (* Menuzeile sperren und Window-Events verhindern *)
  1170.     MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  1171.     MagicAES.WindUpdate (MagicAES.BEGMCTRL);
  1172.     HideMouse();
  1173.     (* Cursor zeigen *)
  1174.     HideCursor (ed);
  1175.     blockIndent := TRUE;
  1176.     multiBlockMark := TRUE;
  1177.     wasMarked := FALSE;
  1178.     FOR i := 0 TO maxMarks DO
  1179.       marks[i].line := -1;
  1180.       marks[i].row := -1;
  1181.     END;
  1182.     marks[0].line := currLineNr;
  1183.     marks[0].row  := currRow;
  1184.     ShowCursor (ed);
  1185.     REPEAT
  1186.       oldLine := currLineNr;
  1187.       oldRow := currRow;
  1188.       (* Event holen *)
  1189.       DoEvent (scan, ch, taste, kstate);
  1190.       Keyboard.GemCharToKey (taste, SHORT (INTEGER(kstate)), key);
  1191.       marked := CatGlobal.WithShift (kstate);
  1192.       IF marked # wasMarked
  1193.       THEN
  1194.         INC (lastMark);
  1195.         IF (lastMark > maxMarks) OR (highMark > maxMarks)
  1196.         THEN
  1197.           DEC (lastMark);
  1198.           (* Abbrechen, maximale Anzahl Marken erreicht *)
  1199.           CatGlobal.Bing (1);
  1200.           key.ch := 'Q';
  1201.           key.ctrl := MOSGlobals.CtrlSet{};
  1202.           key.scan := 0;
  1203.         END;
  1204.         highMark := BinOps.HigherInt (highMark, lastMark);
  1205.       END;
  1206.       ctrl := CatGlobal.WithCtrl (kstate);
  1207.       IF ctrl
  1208.       THEN 
  1209.         kstate := {MagicAES.KCTRL};
  1210.       ELSE
  1211.         kstate := {};
  1212.       END;
  1213.       IF Keyboard.IsSpecial (key)
  1214.       THEN
  1215.         CASE Keyboard.SpecialKey (key) OF
  1216.           home:         EditFuncs.Home (ed, FALSE); |
  1217.           clr:          marked := FALSE;    (* Nicht markieren! *)
  1218.                         EditFuncs.Home (ed, TRUE);  |
  1219.           soln,
  1220.           wdLeft,
  1221.           left:         EditFuncs.CursorLeft (ed, kstate); |
  1222.           eoln,
  1223.           wdRight,
  1224.           right:        EditFuncs.CursorRight (ed, kstate); |
  1225.           pgUp,
  1226.           up:           EditFuncs.CursorUp (ed, ctrl);   |
  1227.           pgDown,
  1228.           down:         EditFuncs.CursorDown (ed, ctrl); |
  1229.         ELSE
  1230.         END; (* CASE *)
  1231.       END (* IF *);
  1232.       IF marked & ((oldLine # currLineNr) OR (oldRow # currRow))
  1233.       THEN
  1234.         MarkArea (ed, oldLine, oldRow, currLineNr, currRow, TRUE);
  1235.       END;
  1236.       marks[lastMark].line := currLineNr;
  1237.       marks[lastMark].row  := currRow;
  1238.       wasMarked := marked;
  1239.       IF marked & ((oldLine # currLineNr) OR (oldRow # currRow))
  1240.       THEN
  1241.         MarkToBlocks ();
  1242.       END;
  1243.     UNTIL (Keyboard.IsASCII (key) & (CAP(key.ch) = 'Q'));
  1244.     
  1245.     (* Cursor zeigen *)
  1246.     HideCursor (ed);
  1247.     multiBlockMark := FALSE;
  1248.     blockIndent := FALSE;
  1249.     block := CatEdit.BlockIsMarked (ed^.wdw);
  1250.     ShowCursor (ed);
  1251.     ShowMouse(FALSE);
  1252.     MagicAES.WindUpdate (MagicAES.ENDMCTRL);
  1253.     MagicAES.WindUpdate (MagicAES.ENDUPDATE);
  1254.   END (* WITH ed^ *)
  1255. END MarkMultiple;
  1256.  
  1257. PROCEDURE JoinLine (ed: EDITPTR);
  1258.   VAR len       : INTEGER;
  1259.       newLen    : INTEGER;
  1260.       qLen      : INTEGER;
  1261.       quoteStr  : ARRAY [0..127] OF CHAR;
  1262.       newText   : textPtr;
  1263. BEGIN
  1264.   WITH ed^ DO
  1265.     IF EditBase.GetLineLength (ed, currLineNr+1, len)
  1266.     THEN
  1267.       (* tempor„re Zeile allozieren *)
  1268.       ALLOCATE (newText, len + 2);
  1269.       IF newText = NIL THEN RETURN END;
  1270.  
  1271.       (* Neue L„nge berechnen *)
  1272.       newLen := len + editLen; 
  1273.       AllocNew (editLine, newLen+2);
  1274.  
  1275.       (* n„chste Zeile holen *)
  1276.       v.bool := EditBase.GetLine (ed, currLineNr+1, newText^, len);
  1277.  
  1278.       (* Quote holen *)
  1279.       GetQuote (editLine.text^, quoteStr);
  1280.       qLen := LENGTH (quoteStr);
  1281.       
  1282.       editLine.text^[editLen-1] := '';
  1283.       Strings.Delete (newText^, 0, qLen, v.bool);
  1284.       Strings.Append (newText^, editLine.text^, v.bool);
  1285.       editLen := LENGTH (editLine.text^);
  1286.  
  1287.       editChanged := TRUE;
  1288.  
  1289.       v.bool := EditBase.PutCurrLine (ed);
  1290.       v.bool := EditBase.DeleteLine (ed, currLineNr+1);
  1291.       IF currLineNr < StartLine
  1292.       THEN
  1293.         DEC (StartLine);
  1294.       END;
  1295.       DEALLOCATE (newText, 0);
  1296.     END;
  1297.   END;
  1298. END JoinLine;
  1299.  
  1300. PROCEDURE BuildOriginalText (ed: EDITPTR);
  1301.   VAR cLine: LONGINT;
  1302. BEGIN
  1303.   (* Jetzt die Zeilen durchgehen *)
  1304.   WITH ed^ DO
  1305.     cLine := 0;
  1306.     SetCurrLine (ed, 1);
  1307.     WHILE cLine < totalLineNr DO
  1308.       SetCurrLine (ed, cLine);
  1309.       IF editLine.text^[editLen-1] = CR
  1310.       THEN
  1311.         (* Hier haben wir umgebrochen *)
  1312.         JoinLine (ed);
  1313.       ELSE
  1314.         INC (cLine);
  1315.       END;
  1316.     END;
  1317.   END;
  1318. END BuildOriginalText;
  1319.  
  1320. VAR     fastWrap:   BOOLEAN;
  1321.  
  1322. PROCEDURE TextWidth (ed: EDITPTR; REF str: ARRAY OF CHAR; idx: INTEGER; VAR width: INTEGER);
  1323.   VAR extend    : ARRAY [0..3] OF Point;
  1324. BEGIN
  1325.   IF fastWrap
  1326.   THEN
  1327.     IF idx < (32767 DIV ed^.charWidth)
  1328.     THEN
  1329.       width := idx * ed^.charWidth;
  1330.     ELSE
  1331.       width := 32767;
  1332.     END;
  1333.   ELSE
  1334.     GetTextWidth (ed, str, idx, extend);
  1335.     width := extend[1].x - extend[0].x;
  1336.   END;
  1337. END TextWidth;
  1338.  
  1339. PROCEDURE WrapLine (ed: EDITPTR; maxWdwWidth: INTEGER);
  1340.   VAR width: INTEGER;
  1341.       lastIdx, 
  1342.       idx  : INTEGER;
  1343.       quoteStr : ARRAY [0..127] OF CHAR;
  1344. BEGIN
  1345.   WITH ed^ DO
  1346.     idx := LENGTH (editLine.text^);
  1347.     REPEAT
  1348.       TextWidth (ed, editLine.text^, idx, width);
  1349.       IF (width > maxWdwWidth)
  1350.       THEN
  1351.         (* umbrechen *)
  1352.         lastIdx := idx;
  1353.         IF monoSpaced 
  1354.         THEN
  1355.           idx := (maxWdwWidth DIV charWidth) - 1;
  1356.         ELSE
  1357.           IF width = 32767
  1358.           THEN
  1359.             idx := BinOps.LowerInt ((maxWdwWidth * 7 DIV 5) DIV charWidth, idx);
  1360.           ELSE
  1361.             (* Erstmal eine Ann„herung berechnen *)
  1362.             DEC (idx, (width - maxWdwWidth) DIV charWidth);
  1363.           END;
  1364.         END;
  1365.         idx := BinOps.LowerInt (idx, lastIdx);
  1366.         DEC (idx);
  1367.         WHILE (idx > 0) & (editLine.text^[idx] # ' ') DO
  1368.           DEC (idx);
  1369.         END;
  1370.         IF idx = 0
  1371.         THEN
  1372.           (* Zwangsumbrechen im Wort *)
  1373.           idx := BinOps.LowerInt (lastIdx, (maxWdwWidth * 7 DIV 5) DIV charWidth);
  1374.           WHILE (width > maxWdwWidth) & (idx > 0) DO
  1375.             DEC (idx);
  1376.             TextWidth (ed, editLine.text^, idx, width);
  1377.           END;
  1378.           IF idx = 0
  1379.           THEN
  1380.             idx := lastIdx;     (* kein Umbruch *)
  1381.             width := maxWdwWidth;
  1382.           END;
  1383.         END;
  1384.       END;
  1385.     UNTIL width <= maxWdwWidth;
  1386.     IF idx < INTEGER(LENGTH (editLine.text^))
  1387.     THEN
  1388.       (* umbrechen, Zeile bei idx trennen *)
  1389.       INC (idx);
  1390.       GetQuote (editLine.text^, quoteStr);
  1391.       (* Wir basteln den Quote nur zusammen, wenn das *)
  1392.       AllocNew (editLine, INTEGER(LENGTH (editLine.text^) + LENGTH (quoteStr) + 5));
  1393.       Strings.Insert (CR, idx, editLine.text^, v.bool);
  1394.       IF idx > INTEGER(LENGTH (quoteStr))
  1395.       THEN
  1396.         Strings.Insert (quoteStr, idx+1, editLine.text^, v.bool);
  1397.         INC (editLen, LENGTH (quoteStr) + 1);
  1398.       ELSE
  1399.         INC (editLen, 1);
  1400.       END;
  1401.       (* Zeile in Buffer schreiben *)
  1402.       editChanged := TRUE;
  1403.       v.bool := EditBase.PutCurrLine (ed);
  1404.       (* Zeile trennen *)
  1405.       v.bool := EditBase.InsertCr (ed, currLineNr, idx+1);
  1406.       IF currLineNr < StartLine
  1407.       THEN
  1408.         INC (StartLine);
  1409.       END;
  1410.     END;
  1411.   END;
  1412. END WrapLine;
  1413.  
  1414. PROCEDURE WrapText (ed: EDITPTR; force: BOOLEAN): BOOLEAN;
  1415.   VAR   cLine    : LONGINT;
  1416.         saveLine : LONGINT;
  1417.         mWidth   : INTEGER;
  1418.         wdwWidth : INTEGER;
  1419.         work     : Rectangle;
  1420. BEGIN
  1421.   (* Umbruch berhaupt eingeschaltet *)
  1422.   IF ~force
  1423.   THEN
  1424.     IF ed^.fileName.text # NIL
  1425.     THEN
  1426.       RETURN FALSE;
  1427.     END;
  1428.     ConfVars.GetConfDefBool (cViewWrap, v.bool, TRUE);
  1429.     IF ~v.bool THEN RETURN FALSE END;
  1430.   END;
  1431.   ConfVars.GetConfDefBool (cViewFastWrap, fastWrap, FALSE);
  1432.   
  1433.   (* Reservebreite holen *)
  1434.   TextWidth (ed, "   ", 2, mWidth);
  1435.   
  1436.   (* Umbruchbreite berechnen *)
  1437.   wdwWidth := ed^.editWork.w - pixOff - mWidth;
  1438.   
  1439.   (* Keine Žnderung? Raus hier! *)
  1440.   IF wdwWidth = ed^.lastWrapWidth THEN RETURN FALSE END;
  1441.  
  1442.   MouseBusy();
  1443.   
  1444.   IF ed^.block
  1445.   THEN
  1446.     EditTools.ClearBlock (ed);
  1447.   END;
  1448.   
  1449.   (* Text wieder in Originalform bringen *)
  1450.   saveLine := ed^.currLineNr;
  1451.   BuildOriginalText (ed);
  1452.   
  1453.   (* Jetzt die Zeilen durchgehen *)
  1454.   WITH ed^ DO
  1455.     (* Umbruchbreite merken *)
  1456.     lastWrapWidth := wdwWidth;
  1457.     cLine := 0;
  1458.     WHILE cLine < totalLineNr DO
  1459.       SetCurrLine (ed, cLine);
  1460.       WrapLine (ed, wdwWidth);
  1461.       INC (cLine);
  1462.     END;
  1463.     maxWidth := 0;
  1464.     SetCurrLine (ed, saveLine);
  1465.     currLineNr := saveLine;
  1466.   END;
  1467.  
  1468.   MouseArrow();
  1469.   RETURN TRUE;
  1470. END WrapText;
  1471.  
  1472. END EditUtil.
  1473.